#!/usr/bin/python

# To change this template, choose Tools | Templates
# and open the template in the editor.

__author__ = "gabor"
__date__ ="$2010.07.07. 20:01:46$"


# Runtime parameters                    # Recommended values

# Prints debug messages with timestamps, useful for developing
__debug_mode__ = 0                      #
# Enables printing information of the process
__log_mode__=1                          #
# Switch between printing to file / printing to screen
__logto_file__=0                        #
# Enables logging of serial port traffic
__log_serial__=0

# Number of attemts to determine if AT command set is supported
__checkat_tries__=10                    # 10
# Number of attempts to build up/ to connect to a ZigBee network
__setup_tries__=20                      # 20
# Number of attempts to get the names of the found devices
__getname_tries__=2                     # 3
# This parameter determines how many unsuccesful reading must occur (one after another) to remove a device
__misread_to_remove__=5                 # 5
# After this number of live data reading cycles, rescanning o the network occurs
__loops_to_rescan__=100                  #
# If parallel data fetching is set in the config file, this option ensures that only __semi_parallel_no__ queries occur simultaneously (seim-parallel mode)
__semi_parallel_mode__=1                # 1
# This number of data queries occur parallel
__semi_parallel_no__=4                  # 4

# Timeout for fetching live data in parallel mode
__live_info_timeout_par__=4             # 4
# Timeout for fetching live data in semi-parallel mode
__live_info4_timeout_par__=4            # 3
# Timeout for fetching live data in setial mode
__live_info_timeout__=4                 # 4
#Timeout at finding devices
__finddevices_timeout__=8               # 8
#Timeout for getting device names in parallel mode
__getnames_timeout_par__=4              # 5
#Timeout for getting device names in semi-parallel mode
__getnames4_timeout_par__=4             # 3
#Timeout for getting device names in serial mode
__getnames_timeout_serial__=4           # 3
#Timeout for getting list of neighbours of a remote node
__get_neighbours_timeout__=5            # 4

#Time interval between sending AT commands in parallel mode
__command_interval__=0.1                # 0.1
#Time interval between parallel data fetching in semi-parallel mode
__unit_interval__=0.2                   # 0.2
#Maximum possible number of devices (not the same as 'expected number of devices' in config file!)
__max_device_no__=24                    #
#Timeout for serial port. Increase if script doesn't work at all (terminates at the beginning)
__serial_port_timeout__=0.06            # 0.05 - 0.1, typ.: 0.7


## DO NOT EDIT BELOW THIS LINE

#######################################################
###   IMPORTS
#######################################################

import threading
import time
import calendar
import datetime
import serial
import copy
import pydot
import gobject
import avahi, dbus, dbus.glib, dbus.service
import sys

#######################################################
### GLOBALS
#######################################################
total_live_data={}  # dictionary for storing actual live datas
devices={}
INT_setting=0


#######################################################
###   FUNCTIONS
#######################################################

# Prints arguments to screen or to file, is used for debug messages (at the development phase)
def print_debug(*args):
    if __debug_mode__:
        t=time.localtime()
        #if logging to screen
        if __logto_file__==0:
            # printing line beginning
            print '\n< DEBUG: %4d.%2.2d.%2.2d.%2.2d:%2.2d.%2.2d: '%(t[0],t[1],t[2],t[3],t[4],t[5]),
            for i in range(len(args)):
                print args[i],
            print '>',
        #else logging to file
        else:
            try:
                log_handle=open('debug.log','a')
                # printing line beginning
                log_handle.write('\n< DEBUG: %4d.%2.2d.%2.2d.%2.2d:%2.2d.%2.2d: '%(t[0],t[1],t[2],t[3],t[4],t[5]))
                for i in range(len(args)):
                    #log_handle.write(str(args[i]))
                    log_handle.write(repr(args[i]))
                log_handle.write('>')
                log_handle.close()
            except IOError:
                return
    return
# prints arguments to file, used for recording messages of serial port
def print_serial(*args):
    if __log_serial__:
        t=time.localtime()
        #if logging to screen

        try:
            log_handle=open('serial.log','a')
            # printing line beginning
            log_handle.write('\n< SERIAL: %4d.%2.2d.%2.2d.%2.2d:%2.2d.%2.2d: %s'%(t[0],t[1],t[2],t[3],t[4],t[5],args[0]))
            for i in range(len(args)-1):
                #log_handle.write(str(args[i]))
                log_handle.write(repr(args[i+1]))
            log_handle.write('>')
            log_handle.close()
        except IOError:
            return
    return

def clear_buffer(s):
    buffer=s.readlines()
    print_serial('Rx:',buffer)


def serialwrite(s,message):
    s.write(message)
    print_serial('Tx:',message)

# Prints arguments to screen or to file, is used for normal messages of program operation
def print_log(*args):
    # funcion is enabled in log mode or in debug mode
    if __debug_mode__|__log_mode__:
        t=time.localtime()
        #if logging to screen
        if __logto_file__==0:
            # printing line beginning
            print '\n%4d.%2.2d.%2.2d.%2.2d:%2.2d.%2.2d: '%(t[0],t[1],t[2],t[3],t[4],t[5]),
            for i in range(len(args)):
                    print args[i],
        #else logging to file
        else:
            try:
                log_handle=open('run.log','a')
                # printing line beginning
                log_handle.write('\n%4d.%2.2d.%2.2d.%2.2d:%2.2d.%2.2d: '%(t[0],t[1],t[2],t[3],t[4],t[5]))
                for i in range(len(args)):
                    log_handle.write(repr(args[i]))
                log_handle.close()

            except IOError:
                return

# Reading bytes from serial port
# s: handler of serial port
# number: number of bytes to read (expected length of message) if received>=number, the fnction returns
# timeout: function returns if received bytes < excepted bytes if 'timeout' time has elapsed.
def readbytes(s,number,timeout):
    bytes=''
    start=time.time()
    while 1:
        input=s.read(number)
        print_serial('Rx:',input)
        bytes+=input
        # if we have 'number' characters received or 'timeout' time is elapsed
        if (len(bytes)>=number) | ((time.time()-start)>timeout):
            break

    return bytes

# Reading lines from serial port in every second for 'tries' second.
# s: handler of serial port
def time_limited_read(s, tries):
    # reads serial input repeatedly 'tries' times with 1 sec interval
    ser_in = []

    for i in range(tries):
        buffer = s.readlines()
        print_serial('Rx:',buffer)
        ser_in.extend(buffer)
        time.sleep(1)
    return ser_in

# Reading lines from serial port
# s: handler of serial port
# excepted: number of lines to read. if 'excepted' number of lines has been read, the function returns
# timeout: funcion returns if 'timeout' time is elapsed, regardless to the number of read lines
def line_limited_read(s, excepted, timeout):
    # reads serial port repeatedly until 'excepted' lines are received or timeout raises
    ser_in = []
    time_start = time.time()
    while 1:
        buffer = s.readlines()
        print_serial('Rx:',buffer)
        ser_in.extend(buffer)
        # if we have received the lines
        if len(ser_in) >= excepted:
            output=ser_in
            break
        # if 'timeout' time is elapsed
        elif (time.time()-time_start) > timeout:
            output=ser_in
            break
    return output

# Checks if the device on the serial port supports AT commands set
# s: handler of serial port
# returns 1 if supports or 0 if not
def is_at(s):

    serialwrite(s,'AT\r\n')

    # Expected response consists of 2 lines
    ser_in=line_limited_read(s,2,1)
    print_debug('Received: ', ser_in)
    if len(ser_in) > 1:
        if ser_in[1] == 'OK\r\n':
            return 1
        else:
            return 0
    else:
        return 0

# Turns off echo of ETRX-R212 on serial port
# s: handler of serial port
# returns 1 if success
def turnoff_echo(s):
    ## Setting S0B register --> Turning off echo

    serialwrite(s,'ATS0B=0510\r\n')

     # Expected response consists of 2 lines
    ser_in=line_limited_read(s,2,1)
    ## DEBUG
    print_debug('Received: ', ser_in)
    if len(ser_in) > 1:
        if ser_in[1] == 'OK\r\n':
            return 1
        else:
            return 0
    else:
        return 0

# Setting PAN_ID register in ETRX-R212
# s: handler of serial port
# returns 1 if success
def set_pan_id(s):
    ## setting PAN_ID

    serialwrite(s,'ATS01=31F4\r\n')

    ser_in=line_limited_read(s,2,1)
    print_debug('Received: ', ser_in)
    if len(ser_in) > 1:
        if ser_in[1] == 'OK\r\n':
            return 1
        else:

            return 0
    else:

        return 0


# Command for ETRX-R212 to leave it's network
# s: handler of serial port
# returns 1 if success
def leave_pan(s):
    ## leaving current network
    serialwrite(s,'AT+DASSL\r\n')

    ser_in = line_limited_read(s, 3, 5)
    print_debug('received after leaving network',ser_in)
    if len(ser_in)>3:
        ## correct ansver
        if (ser_in[1][0:2]=='OK') & (ser_in[3][0:7]=='LeftPAN'):
            return 1
        else:   ## retrying building network
            return 0

# Setting channel mask register in ETRX-R212
# s: handler of serial port
# returns 1 if success
def set_channel_mask(s):
    #setting channel mask

    serialwrite(s,'ATS00=3FFC\r\n')

    ser_in=line_limited_read(s,2,1)
    print_debug('Received: ', ser_in)
    if len(ser_in) > 1:
        if ser_in[1] == 'OK\r\n':

            return 1
        else:

            return 0
    else:

        return 0

# Resets ZigBee module
# s: handler of serial port
# returns a tuple (a,b); where 'a' is 1 if success, 0 if not. 'b' is the 3rd line of answer (information about the joined PAN)
def reset_zigbee(s):
    #resetting Zigbee module

    serialwrite(s,'ATZ\r\n')


    ser_in = line_limited_read(s, 5, 20)
    print_debug('Received: ', ser_in)
    if len(ser_in) > 2:
        if ser_in[2] != 'OK\r\n':
            return (0,'')
        if len(ser_in) > 4:
            if ser_in[4][0:5] == 'JPAN:':

                return (1,ser_in[4])
            else:
                return (0,'')
        else:
            return (0,'')



# Establishes PAN_ID: sets up a ZigBee network as a coordinator
# s: handler of serial port
# returns 1 if success
def est_pan_id(s):
    serialwrite(s,'AT+EN\r\n')

    ser_in = line_limited_read(s, 3, 20)
    print_debug('received after establishing network',ser_in)
    if len(ser_in)>2:
        ## correct answer
        if (ser_in[1][0:5]=='JPAN:')&(ser_in[1][8:12]=='31F4')&(ser_in[2][0:2]=='OK'):
            return 1
        else:
            return 0
# Joins to an existing PAN_ID as a router
# s: handler of serial port
# returns 1 if success
def join_pan(s):
    serialwrite(s,'AT+JN\r\n')

    ser_in = line_limited_read(s, 3, 10)
    print_debug('received after joining network',ser_in)
    return
    if len(ser_in)>2:
        ## correct answer
        if (ser_in[1][0:5]=='JPAN:')&(ser_in[1][8:12]=='31F4')&(ser_in[2][0:2]=='OK'):
            return 1
        else:
            return 0
# Looks for devices in network
# s: handler of serial port
# excepted: excepted number of devices present. 0 means that this number is not determined
#           Setting this value correcly in config file makes finding much faster
# return value is a dictionary: {EUI:role}, where role can be 'router' or 'coordinator'
def find_devices2(s,expected=0):

    ## number of bytes: 2+4+device_no*(24)
    #bytes_no: predicted size of the answer. It is needed for reading without timeout
    if expected>0:
        bytes_no=6+expected*24
    else:
        bytes_no=3+__max_device_no__*24


    starttime=time.time()
    serialwrite(s,'AT+SN\r\n')

    device_role_list={}
    ser_in=readbytes(s,bytes_no,__finddevices_timeout__)
    print_debug('Received: ', ser_in)
    print_log('Found new devices in %f seconds'%(time.time()-starttime))
    for i in range (len(ser_in)-21):
        # If device is a router
        if ser_in[i:i+4]=='FFD:':
            device_role_list[ser_in[i+4:i+20]]='router'
        # if device is a coordinator
        elif ser_in[i:i+4]=='COO:':
            device_role_list[ser_in[i+4:i+20]]='coordinator'
        else:
            pass
    print_debug('Device list: ', device_role_list.keys())

    return device_role_list


# Getting names of the found devices
# s: handler of serial port
# device list: list of EUIs of found devices
# PAR setting: is parallel or serial communication set?
# returns a dictionary: {EUI:name}
def get_device_names(s, device_list,PAR_setting):
#maximum length of a name is 31 characters. Message length for 1 device: 2+11+4+2+8+2+26=55 --> until payload. Payload: 5+name(max31)+13
#max: 73+name=max 104;
    device_data_list = {}
    # Parallel communication
    if PAR_setting=='1':
        # if semi_parallel_mode
        if __semi_parallel_mode__==1:
            dict_payloads=par_get4_binary(s,device_list,'v')
        # parallel mode
        else:
            dict_payloads=par_get_binary2(s,device_list,'v')


        for EUI,payload in dict_payloads.iteritems():
            device_name=binary_to_name(payload)
            if len(device_name) > 0:
                device_data_list[EUI] = device_name
    # serial communication
    else:
        for device_i in range(len(device_list)):
            ## sending 'v' command for device i
            clear_buffer(s)   ## -->emptying buffer

            serialwrite(s,'AT+UCAST:' + device_list[device_i] + '=v\r\n')


            #read until the length parameter (only the header of the mesage)
            ser_in=readbytes(s,55,__getnames_timeout_serial__)

            if (len(ser_in))>54:
                if (ser_in[29:35]=='UCAST:'):
                    # length of the binary payload
                    length=int(ser_in[52:54],16)
                    # calculating number of remained bytes to read
                    remained=55+length+2-len(ser_in)
                    # reading remained part
                    ser_in=ser_in+readbytes(s,remained,__getnames_timeout_serial__)
                # not having length information
                else:
                    remained=104-len(ser_in)
                    ser_in=ser_in+readbytes(s,remained,__getnames_timeout_serial__)
             # not having length information
            else:
                 remained=104-len(ser_in)
                 ser_in=ser_in+readbytes(s,remained,__getnames_timeout_serial__)

            print_debug('Received: ', [ser_in])
            # getting data from answer
            # creating dictionary of payloads from the serial data
            payloads=stream_to_payloads(ser_in,device_list)

            if len(payloads)>0:
                device_name=binary_to_name(payloads[device_list[device_i]])
            else:
                device_name=''

            if len(device_name) > 0:
                device_data_list[device_list[device_i]] = device_name

    print_debug('Device data list: ', device_data_list)

    return device_data_list


# Reads name information from binary payload (for 'v' command)
# payload: string of binary values
# return value: string of name
def binary_to_name(payload):
    ## getting name from binary data
    device_name = ''
    try:
        len_payload=len(payload)
    except TypeError:
        return device_name
    if len_payload>0:
        if ord(payload[2])==51:
            for char_j in range(5,len(payload)-1):
                if payload[char_j] == '\x00':
                    device_name = payload[5:char_j]
                    break
    return device_name

# Fetches maximum RMS voltage,current and wattage from a Plogg device
# s: serial port handler
# device: a tuple describing the target Plogg
# device_list: list of devices (EUIs)
# reset: 1 to reset these maximum values, 0 otherwise
# returns dictionary of maximum values. keys: maxvoltage, maxcurrent, maxwattage
def get_max_values(s,device,device_list,reset):
    #length of answer: 55+payload+2, payload=32 --> 89
    print_log('\nGetting maximum values from %s...\n'%device[1])
    if reset:
        serialwrite(s,'AT+UCAST:'+device[0]+'=ym 1\r\n')

    else:
        serialwrite(s,'AT+UCAST:'+device[0]+'=ym\r\n')

    ## time limited read bec. of binary data: number of received lines cannot be forecast
    ser_in=readbytes(s,89,2)

    print_debug('Received: ', [ser_in],'length',len(ser_in))
     # getting data from answer

    payload=stream_to_payloads(ser_in,device_list)[device[0]]
    max_values={}
    try:
        len_payload=len(payload)
    except TypeError:
        return max_values
    if len_payload>0:
        payload_b=[]
        #convert payload string to list of decimal values
        for i in range(len(payload)):
            payload_b.append(ord(payload[i]))
        ##Tag in binary data
        #tag=payload_b[0]
        ##length of packet
        #length=payload_b[1]
        ## list of live data

        #if we have max RMS voltage
        print_debug('payload:',payload_b)
        #print_debug(payload_b[2],payload_b[7])
        if (payload_b[2]==14) & (payload_b[7]==15):
            value=binarytoint(payload_b[3:7])
            if value>0:
                max_values['maxvoltage']=(binarytotime(payload_b[8:12]),0.001*value)
                print_debug('Max Voltage:',max_values['maxvoltage'])
        ##if we have max RMS current
        if (payload_b[12]==16) & (payload_b[17]==17):
            value=binarytoint(payload_b[13:17])
            if value>0:
                max_values['maxcurrent']=(binarytotime(payload_b[18:22]),0.001*value)
                print_debug('Max Current:',max_values['maxcurrent'])
        ##if we have max wattage value
        if (payload_b[22]==18) & (payload_b[27]==19):
            value=binarytoint(payload_b[23:27])
            if value>0:
                max_values['maxwattage']=(binarytotime(payload_b[28:32]),0.001*value)
                print_debug('Max Wattage:',max_values['maxwattage'])
        return max_values

    return max_values


# Converts 4 bytes of binary message to a 32-bit integer value
# decimalbytes: list of 4 8-bit integer values
# returns 32-bit integer value or "error" string
def binarytoint(decimalbytes):
    if len(decimalbytes)==4:
        u32value=decimalbytes[0]*16777216 + decimalbytes[1]*65536 + decimalbytes[2]*256 + decimalbytes[3]
        return u32value
    else:
        return "error"

# Converts 4 bytes of binary message to date, time values
# decimalbytes: list of 4 8-bit integer values
# returns a tuple: (year,month,day,hour,min,sec) or () if error
def binarytotime(decimalbytes):
    if len(decimalbytes)==4:
        u32value=binarytoint(decimalbytes)
        year=((u32value&4227858432)>>26)+2000
        month=((u32value&62914560)>>22)+1
        day=((u32value&4063232)>>17)+1
        hour=((u32value&126976)>>12)
        min=((u32value&4032)>>6)
        sec=u32value&63
        return (year,month,day,hour,min,sec)
    else:
        return ()

# Converts 32-bit integer value to time
# u32value: 32-bit integer
# returns a tuple: (year,month,day,hour,min,sec)
def inttotime(u32value):
    year=((u32value&4227858432)>>26)+2000
    month=((u32value&62914560)>>22)+1
    day=((u32value&4063232)>>17)+1
    hour=((u32value&126976)>>12)
    min=((u32value&4032)>>6)
    sec=u32value&63
    return (year,month,day,hour,min,sec)


# Gets binary information from multiple Ploggs parallel. For 'v' and 'yv' commands
# s: serial port handler
# device_list: list of EUIs of devices
# PloggCommand: 'v' for getting names, 'yv' for getting live info
# returns dictionary of binary payload of the answers: {EUI:binary payload}
def par_get_binary2(s,device_list,PloggCommand):
    #iterating on devices
    for i in range(len(device_list)):
        serialwrite(s,'AT+UCAST:%s=%s\r\n'%(device_list[i],PloggCommand))

        # pause between sending command
        time.sleep(__command_interval__)
    if PloggCommand=='yv':
        meslength=112
        timeout=__live_info_timeout_par__
    elif PloggCommand=='v':
        meslength=104
        timeout=__getnames_timeout_par__
    #Reading serial port
    message=readbytes(s,len(device_list)*meslength,timeout)
    print_debug('Received parallel: ', message)
    # Getting binary payloads out from the received
    payloads={}
    # converting serial input to dictionary of payloads
    payloads=stream_to_payloads(message,device_list)
    return payloads

# Gets binary information from multiple Ploggs semi-parallel. For 'v' and 'yv' commands
# s: serial port handler
# device_list: list of EUIs of devices
# PloggCommand: 'v' for getting names, 'yv' for getting live info
# returns dictionary of binary payload of the answers: {EUI:binary payload}
def par_get4_binary(s,device_list,PloggCommand):
    payloads={}
    device4_list=[]
    part=[]
    #cutting device list to pieces of '__semi_parallel_no__' device
    for i in range(len(device_list)):
        part.append(device_list[i])
        #print_debug('part:',part)
        # if __semi_parallel_no__ part is collected -> appending to final list
        if i%__semi_parallel_no__==(__semi_parallel_no__-1):
            device4_list.append(part)
            part=[]
    # if the size of last segment != __semi_parallel_no__
    if ((len(device_list)-1)%__semi_parallel_no__)!=(__semi_parallel_no__-1):
        device4_list.append(part)
    print_debug('device4_list:',device4_list)
    #emptying input buffer
    #clear_buffer(s)
    for unit in range(len(device4_list)):
        clear_buffer(s)
        for i in range(len(device4_list[unit])):
            serialwrite(s,'AT+UCAST:%s=%s\r\n'%(device4_list[unit][i],PloggCommand))

            # pause between sending command
            time.sleep(__command_interval__)

        if PloggCommand=='yv':
            meslength=112
            timeout=__live_info4_timeout_par__
        elif PloggCommand=='v':
            meslength=104
            timeout=__getnames4_timeout_par__
         #Reading serial port
        message=readbytes(s,len(device4_list[unit])*meslength,timeout)
        print_debug('Received parallel (%d): '%len(device_list[unit]), message)
        # Getting binary payloads out from the received
        payload={}
        # converting serial input to dictionary of payloads
        payload=stream_to_payloads(message,device_list)
        #appending to 'payloads
        for k,v in payload.iteritems():
            payloads[k]=v

        #sleep between units
        time.sleep(__unit_interval__)

    print_debug('Overall payloads:',payloads)
    return payloads

# Converts serial input (binary answers form Ploggs) to a dictionary of binary payloads
# longline: serial input 8string)
# device_list: list of EUIs of devices
# returns dictionary: {EUI:payload}

def stream_to_payloads(longline,device_list):
    pointer=0
    progress=0
    current_EUI=''
    temporary={}
    payloads={}
    #temporary structure for data storage:
    for i in range(len(device_list)):
        temporary[device_list[i]]=([0],[0],[''])

    #State machine
    while 1:
        #print_debug('position:%d/%d'%(pointer,len(longline)))
        #Normal state machine -> if pointer is not near the end of the stream
        if (pointer<len(longline)-25):

            # if new answer is detected at this position, and it doesn't interrupts another one
            if (progress==0) & ((longline[pointer:pointer+6]=='UCAST:') & (longline[pointer+22]==',') & (longline[pointer+25]=='=')):

                progress=1
                current_EUI=longline[pointer+6:pointer+22]
                #length of payload
                payload_length=int(longline[pointer+23:pointer+25],16)
                # storing length in temporary structure
                temporary[current_EUI][0][0]=payload_length
                #Forwarding pointer to the beginning of the binary payload
                print_debug('New pattern is discovered at %d, EUI: %s, length: %d'%(pointer,current_EUI,payload_length))
                # forwarding pointer to the beginning of the binary message
                pointer+=26

                continue
            #normal payload copying -> new message header is not discovered at this position and copying isi n progress

            elif (progress==1) & (not((longline[pointer:pointer+6]=='UCAST:') | (longline[pointer:pointer+2]=='OK') | (longline[pointer:pointer+4]=='ACK:'))):
                # if we haven't received the full message yet
                if temporary[current_EUI][1][0]<temporary[current_EUI][0][0]:
                    #copying byte:
                    temporary[current_EUI][2][0]=temporary[current_EUI][2][0]+longline[pointer]
                    #increasing size
                    temporary[current_EUI][1][0]+=1
                    #increasing pointer
                    #print_debug('Copying from %d position to %s'%(pointer,current_EUI))
                    pointer+=1

                    continue
                #End of the copied message
                else:
                    progress=0
                    # Copying to return structure
                    payloads[current_EUI]=temporary[current_EUI][2][0]
                    print_debug('End of message of %s at %d'%(current_EUI,pointer))
                    current_EUI=''

                    # pointer doesn't need to increase now
                    continue
            # new message interrupts the current one --> new message discovered while copying the previous one
            elif (progress==1) & ((longline[pointer:pointer+6]=='UCAST:') | (longline[pointer:pointer+2]=='OK') | (longline[pointer:pointer+4]=='ACK:')):
                #starting to record the new message as the progress wolud be 0:
                print_debug('New message interrupts!')
                progress=0
                continue
            # not interesting part of the stream -> copying isn't in progress and new message is not detected at this position
            elif (progress==0) & (not((longline[pointer:pointer+6]=='UCAST:') & (longline[pointer+22]==',') & (longline[pointer+25]=='='))):

                pointer+=1
                continue
            #invalid state
            else:
                pass
        #near the end of the stream: no need to discover new message header
        elif pointer<len(longline):
            if progress==1:
                ## copying remaining parts
                if temporary[current_EUI][1][0]<temporary[current_EUI][0][0]:
                    #copying byte:
                    temporary[current_EUI][2][0]=temporary[current_EUI][2][0]+longline[pointer]
                    #increasing size
                    temporary[current_EUI][1][0]+=1
                    #increasing pointer
                    #print_debug('(end part)Copying from %d position to %s'%(pointer,current_EUI))
                    pointer+=1
                    continue
                #End of this message
                else:
                    progress=0
                    # Copying to return structure
                    payloads[current_EUI]=temporary[current_EUI][2][0]
                    current_EUI=''
                    # pointer doesn't need to increase now
                    print_debug('end')
                    break
            else:
                break
        else:
              break


    #DEBUG
    print_debug('Temporary:')
    for k,v in temporary.iteritems():
        print_debug(k,'\t',[v])

    #DEBUG
    print_debug('Payload dict:')
    for k,v in payloads.iteritems():
        print_debug(k,'\t',[v])

    return payloads

# processes binary payload (answer for 'yv' command)
# payload: string of binary payload
# name: name of the device whitch is fetched
# EUI: EUI of the device whitch is fetched
# Returns a dictionary with keys: year, month, day, hour, min, sec, watts, cg_watts, cc_watts, freq, voltage, current, ontime, vars, cg_vars, cc_vars, phase, eq_ontime, name, EUI
def binary_to_liveinfo(payload,name,EUI):

    try:
        len_payload=len(payload)
    except TypeError:
        return (live_data,newdevice)
    # list of 32 bit integer values
    raw_data=[]
    live_data={}
    if len_payload>3:
        payload_b=[]
        #convert payload to decimal 8-bit values
        for i in range(len(payload)):
            payload_b.append(ord(payload[i]))

        ##Tag in binary data
        #tag=payload_b[0]
        ##length of packet
        length=payload_b[1]

        ## if value code is 50 --> live data
        if (length == 53) & (len(payload) == 55) & (payload_b[2]==50):
            # convert 8-bit values to 32-bit values
            for i in range(13):
                index=i*4+3
                raw_data.append(binarytoint(payload_b[index:(index+4)]))

            #print_debug('raw data: ',raw_data)

            ## calculating values from raw integers
            ## date and time
            datetime=inttotime(raw_data[0])
            live_data['year']=datetime[0]
            live_data['month']=datetime[1]
            live_data['day']=datetime[2]
            live_data['hour']=datetime[3]
            live_data['min']=datetime[4]
            live_data['sec']=datetime[5]

            ## Watts
            ## if the value is negative
            if (raw_data[1]&2147483648):
                # Format: Sign bit (not two's complement)
                watts=(-1)*(raw_data[1]&2147483647)*0.001
            else:
                watts=raw_data[1]*0.001

            live_data['watts']=watts

            ## Cumulative Watts (Gen)
            live_data['cg_watts']=raw_data[2]*0.0001

            ## Cumulative Watts (Con)
            live_data['cc_watts']=raw_data[3]*0.0001

            ## Frequency
            live_data['freq']=raw_data[4]*0.1

            ## RMS voltage
            live_data['voltage']=raw_data[5]*0.001

            ## RMS current
            live_data['current']=raw_data[6]*0.001

            ## PLOGG on time
            live_data['ontime']=raw_data[7]*0.01

            ## Reactive power
            ## if the value is negative
            if (raw_data[8]&2147483648):
                # Format: Sign bit (not two's complement)
               vars=(-1)*(raw_data[8]&2147483647)*0.001
            else:
                vars=raw_data[8]*0.001
            #print_debug('Reactive power:',vars)
            live_data['vars']=vars

            ## Acc Reactive Power (Gen)
            live_data['cg_vars']=raw_data[9]*0.0001

            ## Acc Reactive Power (Gen)
            live_data['cc_vars']=raw_data[10]*0.0001

            ## phase angle
            phase=raw_data[11]
            ## correcting phase if between 180-360
            if phase>180:
                phase=phase-360
            #print_debug('Phase angle',phase)
            live_data['phase']=phase

            ## Equipment on time
            live_data['eq_ontime']=raw_data[12]*0.01

            ## Adding device EUI and device name to the dictionary
            live_data['name']=name
            live_data['EUI']=EUI

            print_debug('Payload before being processed:',payload)
            print_debug('Payload decimally:',payload_b)
            print_debug('Raw data:',raw_data)
            print_debug('Live data from binary:',live_data)

    return live_data


# Gets live info from a Plogg device
# s: derial port handler
# device: tuple which describes a device
# device_list: list of EUIs of devices
# returns dictionary of live data
def get_live_info2(s,device,device_list):
    #live_data={}
    print_log('Getting live info from',device[1],'...[BINARYMODE]')
    ## EMPTYING BUFFER
    clear_buffer(s)
    serialwrite(s,'AT+UCAST:'+device[0]+'=yv\r\n')

    # reading 112 bytes
    message=readbytes(s,112,__live_info_timeout__)
    print_debug('Received %d bytes: '%len(message),message)
    # getting payload from answer
    payloads=stream_to_payloads(message,device_list)
    # getting values from payload
    if payloads.has_key(device[0]):
        live_data=binary_to_liveinfo(payloads[device[0]],device[1],device[0])
    else:
        live_data={}
     # getting data from answer
    return live_data

# Prints live data to file
# live_data: dictionary of live information from Plogg
# returns 1 if success, 0 if not
##def log_live_data(bus,live_data):
##    #slicing dictionary
##    live_data_string={'EUI':live_data['EUI'],'name':live_data['name']}
##    live_data_float=live_data;
##    del live_data_float['EUI']
##    del live_data_float['name']
##
###    live_data_string.append()
##    try:
##
##        Pm_logger = dbus.Interface(bus.get_object('ca.amk.pm_logger', '/'),'ca.amk.Interface')
##        result=Pm_logger.f_print_live_data(live_data_string,live_data_float)
##
##
##    except dbus.exceptions.DBusException,err:
##        print_debug(str(err))
##        print_log('Logging service isn\'t running.')
##        return 0
##
##
##    return result




# Prints live information from a Plogg to the screen (for interactive mode)
# live_data: dictionary of live information from Plogg
# no return value
def print_live_data(live_data):
    ## if live_data is complete (it has to be!)
    if (live_data.has_key('name')) & (live_data.has_key('EUI')) & (len(live_data)==20):
        print_log("Live data from "+live_data['name']+":")
        #Date and time
        print_log("Device time:          %4d. %2.2d. %2.2d.  %2.2d:%2.2d.%2.2d"%(live_data['year'],live_data['month'],live_data['day'],live_data['hour'],live_data['min'],live_data['sec']))
        #Plogg uptime
        upday=int(live_data['ontime']/86400)
        uphour=int(live_data['ontime']/3600-upday*24)
        upminute=int(live_data['ontime']/60-upday*1440-uphour*60)
        upsec=live_data['ontime']-upday*86400-uphour*3600-upminute*60
        print_log("Plogg Uptime:         %d days %2.2d:%2.2d %5.2f"%(upday,uphour,upminute,upsec))

        #Equipment on time
        upday=int(live_data['eq_ontime']/86400)
        uphour=int(live_data['eq_ontime']/3600-upday*24)
        upminute=int(live_data['eq_ontime']/60-upday*1440-uphour*60)
        upsec=live_data['eq_ontime']-upday*86400-uphour*3600-upminute*60
        print_log("Equipment On Time:    %d days %2.2d:%2.2d %5.2f\n"%(upday,uphour,upminute,upsec))

        # Other values
        print_log("Effective power:      %-.3f W"%live_data['watts'])
        print_log("Generated power:      %-.4f kWh"%live_data['cg_watts'])
        print_log("Consumed power:       %-.4f kWh\n"%live_data['cc_watts'])

        print_log("Frequency:            %-.1f Hz"%live_data['freq'])
        print_log("RMS Voltage:          %-.3f V"%live_data['voltage'])
        print_log("RMS Current:          %-.3f A\n"%live_data['current'])

        print_log("Reactive power:       %-.3f var"%live_data['vars'])
        print_log("Generated r. power:   %-.4f kvarh"%live_data['cg_vars'])
        print_log("Consumed r. power:    %-.4f kvarh"%live_data['cc_vars'])
        print_log("Phase angle:          %d Degrees"%live_data['phase'])

    else:
        print_log('Error while getting live data')

    return

# Sets RTC of a Plogg as the computer time
# s: serial port handler
# device: tuple describes a device
# returns 1 if success, 0 if not
def set_rtc(s,device):
    ## updating plogg's RTC with comuter time


    ## setting date
    t=time.localtime()
    serialwrite(s,'AT+UCAST:'+device[0]+'=RTD%d.%d.%d\r\n'%((t[0]-2000),t[1],t[2]))

#ITT TARTOk SERIALWRITE-tal

    print_debug('RTD command:','AT+UCAST:'+device[0]+'=RTD%d.%d.%d\r\n'%((t[0]-2000),t[1],t[2]))
    ser_in=line_limited_read(s,5,2)
    print_debug('Received: ', ser_in)
    # Checking answer
    if len(ser_in)<5:
        return 0
    if (ser_in[1][0:7]!='+UCAST:') | (ser_in[2][0:2]!='OK') | (ser_in[4][0:4]!='ACK:') | (ser_in[1][7:9]!=ser_in[4][4:6]):
        return 0

    ## setting time
    t=time.localtime()
    serialwrite(s,'AT+UCAST:'+device[0]+'=RTT%d.%d.%d\r\n'%(t[3],t[4],t[5]))

    print_debug('RTT command:','AT+UCAST:'+device[0]+'=RTT%d.%d.%d\r\n'%(t[3],t[4],t[5]))
    ser_in=line_limited_read(s,5,1)
    print_debug('Received: ', ser_in)
    # Checking answer
    if len(ser_in)<5:
        return 0
    if (ser_in[1][0:7]!='+UCAST:') | (ser_in[2][0:2]!='OK') | (ser_in[4][0:4]!='ACK:') | (ser_in[1][7:9]!=ser_in[4][4:6]):
        return 0
    # Successful operation:
    return 1



# Resets accumulated values of a Plogg (kWh, varh quantities)
# s: serial port handler
# device: tuple which describes a device
# device_list: list of EUIs of devices
# returns 1 if success, 0 if not
def reset_acc(s,device,device_list):
    # Length of payload: 7, length of message: 55+7+2=64
    print_log('Resetting accumulators...')
    serialwrite(s,'AT+UCAST:'+device[0]+'=yr\r\n')


    ser_in=readbytes(s,64,__getnames_timeout_serial__)
    print_debug('Received: ', [ser_in])
    payload=stream_to_payloads(ser_in,device_list)[device[0]]

    if len(payload)>0:
        ##Tag in binary data
        #tag=ord(payload[0])
        ##length of packet
        length=ord(payload[1])
        print_debug('Payload: ', payload)
        # Checking answer
        if (length==5)&(ord(payload[2])==20)&(ord(payload[6])==36):
            return 1

    return 0

# Turns off relay in a Plogg
# s: serial port handler
# device: tuple which describes a device
# device_list: list of EUIs of devices
# returns 1 if success, 0 if not
def turnoff(s,device,device_list):
    #Enabling timers without specifying time intervals
    # Setting 0000 on and off times and enabling timer
    # length of the received message: 55+payload+2=55+7+2=64 when enabling/disabling
    #55+20+2 when setting timer =77
    # setting timer0 to 0000-0000
    serialwrite(s,'AT+UCAST:'+device[0]+'=yo 0 0000 0000\r\n')


    ser_in=readbytes(s,77,__getnames_timeout_serial__)

    print_debug('Received: ', [ser_in])
    #payload=get_binary_payload(ser_in,device[0])
    payload=stream_to_payloads(ser_in,device_list)[device[0]]
    if len(payload)>0:
        ##Tag in binary data
        #tag=ord(payload[0])
        ##length of packet
        #length=ord(payload[1])
        print_debug('Payload: ', payload)
        #checking value code
        if (ord(payload[2])==34) & (len(payload)==20):
            # reads if timer is enabled
            noneedtoenable=ord(payload[3])
            # reads which timers need to be reseted
            timertoreset=[]
            for i in range(4,len(payload)):
                if ord(payload[i])!=0:
                    timertoreset=append(int(i/4)-1)
            timertoreset=set(timertoreset)
            print_debug('Timers to reset:',timertoreset)
        else:
            return 0
    else:
        return 0
    ## Resetting reminingtimers
    for i in timertoreset:
        serialwrite(s,'AT+UCAST:'+device[i]+'=yo %d 0000 0000\r\n'%i)


        ser_in=readbytes(s,77,__getnames_timeout_serial__)
        print_debug('Received: ', [ser_in])
        #payload=get_binary_payload(ser_in,device[0])
        payload=stream_to_payloads(ser_in,device_list)[device[0]]
        if len(payload)>0:
            ##Tag in binary data
            #tag=ord(payload[0])
            ##length of packet
            #length=ord(payload[1])
            print_debug('Payload: ', payload)
            if (ord(payload[2])==34) & (len(payload)==20):
                pass
            else:
                return 0
        else:
            return 0

    if noneedtoenable==0:
        ##Enabling timer
        serialwrite(s,'AT+UCAST:'+device[0]+'=ye 1\r\n')

        ser_in=readbytes(s,64,__getnames_timeout_serial__)
        print_debug('Received: ', [ser_in])
        #payload=get_binary_payload(ser_in,device[0])
        payload=stream_to_payloads(ser_in,device_list)[device[0]]
        if len(payload)>0:
            ##Tag in binary data
            #tag=ord(payload[0])
            ##length of packet
            #length=ord(payload[1])
            print_debug('Payload: ', payload)
            if (len(payload)==7):
                if (ord(payload[2])==20) &(ord(payload[6])==28):
                    return 1
        return 0
    else:
        return 1


# Turns on relay in a Plogg
# s: serial port handler
# device: tuple which describes a device
# device_list: list of EUIs of devices
# returns 1 if success, 0 if not
def turnon(s,device,device_list):
    #Disabling timers
    serialwrite(s,'AT+UCAST:'+device[0]+'=ye 0\r\n')

    ser_in=readbytes(s,64,__getnames_timeout_serial__)

    print_debug('Received: ', [ser_in])

    payload=stream_to_payloads(ser_in,device_list)[device[0]]
    if len(payload)>0:
        ##Tag in binary data
        #tag=ord(payload[0])
        ##length of packet
        #length=ord(payload[1])
        if (len(payload)==7):
            if (ord(payload[2])==20) &(ord(payload[6])==29):
                return 1
    return 0

# Sets name of Plogg
#s: serial port handler
# device: tuple which describes a device
# device_list: list of EUIs of devices
# newname: new name of the Plogg
# returns 1 if success, 0 if not
def setname(s,device,device_list,newname):
# maximum length of a name is 31 characters. Message length for 1 device: 2+11+4+2+8+2+26=55 --> until payload. Payload: 3+name(max31)+2
#max: 60+name=max 91;

    serialwrite(s,'AT+UCAST:'+device[0]+'=yn '+newname+'\r\n')
    print_serial('Tx:','AT+UCAST:'+device[0]+'=yn '+newname+'\r\n')
    #read until the length parameter
    ser_in=readbytes(s,55,__getnames_timeout_serial__)

    if (len(ser_in))>54:
        if (ser_in[29:35]=='UCAST:'):
            length=int(ser_in[52:54],16)
            # calculating number of bytes that is not read yet
            remained=55+length+2-len(ser_in)
            # reading remained bytes
            ser_in=ser_in+readbytes(s,remained,__getnames_timeout_serial__)
        else:
            # reading remained bytes
            remained=91-len(ser_in)
            ser_in=ser_in+readbytes(s,remained,__getnames_timeout_serial__)
    else:
        # reading remained bytes
         remained=91-len(ser_in)
         ser_in=ser_in+readbytes(s,remained,__getnames_timeout_serial__)


    print_debug('Received: ', ser_in)
    payload=stream_to_payloads(ser_in,device_list)[device[0]]

    #payload=get_binary_payload(ser_in,device[0])
    device_name = ''
    if len(payload)>0:
        ##Tag in binary data
        #tag=ord(payload[0])
        ##length of packet
        length=ord(payload[1])
        print_debug('Payload: ', payload)

        if len(payload)>0:
            ## getting name from binary data
            # checking answer
            if ord(payload[2])==37:
                device_name=payload[3:len(payload)]

        print_debug('New device name:',device_name)
    if device_name==newname:
        return 1
    else:
        return 0

# Reads information about the USB stick
# s: serial port handler
# returns (name,type,EUI) tuple: name. type and EUI of the USB stick
# returns (--,--,--) in case of any error
def get_owneui(s):
    ## Emptying buffer
    clear_buffer(s)
    serialwrite(s,'ATI\r\n')

    ser_in=line_limited_read(s,5,2)
    print_debug('Received: ', ser_in)
    EUI=''
    if len(ser_in)>4:
        if (ser_in[1]=='Telegesis ZigBee\r\n')&(len(ser_in[3])==18):
            EUI=ser_in[3][0:16]
            name=ser_in[1][0:len(ser_in[1])-2]
            type=ser_in[2][0:len(ser_in[2])-2]
        else:
            name=type=EUI='--'
    return (name,type,EUI)

# Reads neighbours of the USB stick
# s: soerial port handler
# device_list: list of EUIs of devices
# Returns list of EUIs of neighbouring devices
def get_ngbtable(s,device_list):
    ## Emptying buffer
    clear_buffer(s)
    serialwrite(s,'AT+NTABLE?\r\n')

    ser_in=time_limited_read(s,1)
    print_debug('Received: ', ser_in)
    TABLE=[]
    if len(ser_in)>3:
        for i in range(2,len(ser_in)-1):
            #Filtering incorrect EUIs, e.g. 0000000000000000
            if ser_in[i][43:59] in device_list:
                TABLE.append(ser_in[i][43:59])

    return TABLE

# Reads strength of a link between USB stick and a device
# s: serial port handler
# EUI: EUI of the device
# returns (lqi,rssi) tuple (lqi: link quality (prop. to SNR ratio), rssi: received signal strength in dBm)
def get_linkinfo(s,EUI):
    ## Emptying buffer
    clear_buffer(s)
    serialwrite(s,'AT+LINKCHECK:%s\r\n'%EUI)

    ser_in=line_limited_read(s,3,2)
    print_debug('Received: ', ser_in)
    if (len(ser_in)==3):
        if (ser_in[1][0:11]=='+LINKCHECK='):
            rssi=ser_in[1][11:14]
            lqi=ser_in[1][15:17]
            return (lqi,rssi)

    return ('0','0')

# Reads neighbours of a remote node
# s: serial port handler
# EUI: EUI of the device
# returns list of EUIs of neighbouring devices
def get_neighbours(s,EUI):
    clear_buffer(s)
    serialwrite(s,'AT+REMSN:%s\r\n'%EUI)

    ser_in=time_limited_read(s,__get_neighbours_timeout__)
    print_debug('Received: ', ser_in)
    neighbours=[]
    if len(ser_in)>3:
        for i in range(3,len(ser_in)):
            if ser_in[i][0:3]=='REM':
                neighbours.append(ser_in[i][7:23])


    return neighbours

# Prints information of the available devices to the screen (used in interactive mode)
# devices: Dictionary of devices
def print_device_list(devices):
    print_debug('List of devices:',devices)
    output_string='Available devices:\n\nIndex    EUI\x09\x09     Name'
    for i in range(len(devices)):
       #output_string=output_string+(i,'\x09',devices[i][0],'\x09',devices[i][1])
       output_string=output_string+'\n%d\t%s\t%s'%(i,devices[i][0],devices[i][1])

    print_log(output_string)

    return

# Prints the tree representation of a depth-first-search of the network to a file. Recursive function!
# f_handle: file handler
# EUI: EUI of the current node in the search
# devices: dictionary of the devices
# printed_EUI_list: list of devices that have been printed previously
# indent: level of the search (level in tree)
def print_tree_depth(f_handle,EUI,devices,printed_EUI_list,indent):
    #indentation
    for i in range(indent):
        f_handle.write("\t")
    f_handle.write("--> %s\n"%devices[EUI][1])
    printed_EUI_list.append(EUI)
    for EUI_nbr in devices[EUI][5]:
        if (EUI_nbr in printed_EUI_list):
            pass
        else:
            print_tree_depth(f_handle,EUI_nbr,devices,printed_EUI_list,indent+1)

    return

# Prints the tree representation of a breadth-first-search of the network to a file. Recursive function!
# f_handle: file handler
# EUI: EUI of the current node in the search
# devices: dictionary of the devices
# printed_EUI_list: list of devices that have been printed previously
# indent: level of the search (level in tree)
def print_tree_breadth(f_handle,EUI,devices,printed_EUI_list,indent):
    #indentation
    toprint_list=[]
    for i in range(indent):
        f_handle.write("\t")
    f_handle.write("--> %s\n"%devices[EUI][1])
    for EUI_nbr in devices[EUI][5]:
        if (EUI_nbr in printed_EUI_list):
            pass
        else:
            toprint_list.append(EUI_nbr)
            printed_EUI_list.append(EUI_nbr)

    for EUI_nbr in toprint_list:

        print_tree_breadth(f_handle,EUI_nbr,devices,printed_EUI_list,indent+1)

    return

# Generates graph of the network topology to a .png file
# devices: dictionary of devices
# dev_role_list: dictionary of devices and their ZigBee roles
# timestring: string of current date and time
def  gengraph(devices,dev_role_list,timestring):
    graph=pydot.Dot(graph_type='graph')
    #Creating nodes
    #nodelist={}
    edge_tuples=[]
    print_debug("Creating graph...")
    for k,device in devices.iteritems():
        #if coordinator
        if dev_role_list[k]=='coordinator':
            par_style="filled"
            par_fillcolor="#F9A586"
            par_shape="box"
            #if router
        elif dev_role_list[k]=='router':
            par_style="filled"
            par_fillcolor="#B3F4FC"
            par_shape="ellipse"
        else:
            par_style="filled"
            par_fillcolor="#FFFFFF"
            par_shape="ellipse"

        #nodelist[k]=pydot.Node(device[1],style=par_style,fillcolor=par_fillcolor,shape=par_shape)
        gv_node=pydot.Node(device[1],style=par_style,fillcolor=par_fillcolor,shape=par_shape)
        #Adding node to graph
        graph.add_node(gv_node)
        print_debug("\tAdding node %s..."%device[1])
        for i in range(len(device[5])):
            print_debug("\t\tAdding edge...:",(device[1],devices[device[5][i]]))
            edge_tuples.append((device[1],devices[device[5][i]][1]))

    #creating edges
    print_debug("Creating edges...")
    while 1:
        if len(edge_tuples)==0:
            break
        else:
            # current edge: edge_tuples[0]
            start=edge_tuples[0][0]
            end=edge_tuples[0][1]
            #if the opposite edge is present
            print_debug("Start: %s, End: %s"%(start,end))
            if (end,start) in edge_tuples:
                par_dir="both"
                print_debug("\tBidirectional")
                #removing this edge
                edge_tuples.remove((end,start))
            else:
                par_dir="forward"
            #removing the edge
            edge_tuples.pop(0)
            # creating edge
            gv_edge=pydot.Edge(start,end,dir=par_dir)
            graph.add_edge(gv_edge)


    #Creating image
    graph.write_png('maps/network_map_%s.png'%timestring)

    return




#######################################################
###   MAIN FUNCTION (state machine)
#######################################################

def main():

    global devices
    global live_data
   
    #bus = dbus.SessionBus()
    ## initial state
    state='SERIAL'

    ## Main loop for state machine
    while 1:
        try:

            ##########################################################
            ## SERIAL: Reading config file and opening serial port
            ##########################################################
            if state=='SERIAL':
                ## opening config file to read essential parameters
                try:
                    f_config_handle=open('mit_pm_config.dat')
                    configlines=f_config_handle.readlines()
                    print_log('mit_pm_config.dat opened.')
                    print_debug('Config file:',configlines)
                    f_config_handle.close()


                except IOError:
                    print_log('ERROR when reading mit_pm_config.dat! Program terminates...')
                    #sys.exit()
                    return

                if len(configlines)<19:
                    print_log('ERROR when reading mit_pm_config.dat! Program terminates...')
                    #sys.exit()
                    return


                ## Parameters form config file
                try:
                    serial_port_id=configlines[2][0:len(configlines[2])-1]
                    RTC_setting=configlines[4][0]
                    MAP_setting=configlines[6][0]
                    GRAPH_setting=configlines[8][0]
                    INT_setting=int(configlines[10][0:(len(configlines[10]))])
                    ROLE_setting=configlines[12][0:3]
                    PAR_setting=configlines[14][0]
                    MENU_setting=configlines[16][0]
                    expected_device_no=int(configlines[18][0:(len(configlines[10]))])
                except Exception:
                    print_log('ERROR when reading parameters from mit_pm_config.dat! Program terminates...')
                    #sys.exit()
                    return

                ## Creating and setting serial port
                ser = serial.Serial()
                ser.baudrate = 19200
                ser.port = serial_port_id
                ser.parity = 'N'
                ser.stopbits = 1
                ser.xonxoff = 0
                ser.rtscts = 0
                ser.timeout = __serial_port_timeout__   #
                ser.bytesize = 8

                print_log("Created serial port: ", ser)

                ## opening port
                try:
                    ser.open()
                except serial.SerialException:
                    print_log("Failed to open the given serial port! Program terminates...")
                    #sys.exit()
                    return

                ## Serial port opened
                print_log('Serial port opened.')
                state='CHECKAT'
                checkat_counter=0
                continue
                ##End of state 'SERIAL'

            #############################################################
            ## CHECKAT: Checking if AT command set is supported
            #############################################################
            elif state=='CHECKAT':
                ## Check if AT command set supported
                print_log('Checking if AT command set is supported...')
                error = is_at(ser)
                if error == 0:
                    # AT command set not supported -> retrying
                    checkat_counter+=1
                    if checkat_counter<__checkat_tries__:
                        print_log('Wrong answer from device. Retrying #%d'%checkat_counter)
                        ## Emtying RxD buffer
                        clear_buffer(ser)
                        state='CHECKAT'
                        continue
                    else:
                        # We have already had lots of attempts
                        print_log('AT command set is not supported. You perhaps use a not compatible device. Program terminates...')
                        ser.close()
                        #sys.exit()
                        return
                # supported
                else:
                    print_log('AT command set is supported')
                    checkat_counter=0
                    state='SETUP'
                    setup_counter=0
                    continue

            #############################################################
            ## SETUP: setup ZigBee network, Phase 1: Setting registers and resetting USB stick
            #############################################################
            elif state=='SETUP':
                ## Setting up network
                ## turning off echo
                print_log('Turning of echo..')
                error = turnoff_echo(ser)
                if error == 0:

                    setup_counter+=1
                    if setup_counter<__setup_tries__:

                        ##retrying
                        print_log('ERROR at turning off echo. Retrying #%d'%setup_counter)
                        clear_buffer(ser)

                        state='SETUP'
                        continue
                    else:
                        print_log('Unable to set up Zigbee network: Too many errors. Program terminates... ')
                        ser.close()
                        #sys.exit()
                        return
                print_log('Echo has been turned off successfully')

                ## setting PAN_ID register
                error=set_pan_id(ser)
                print_log('Setting PAN_ID...')
                if error == 0:
                    ##retrying
                    setup_counter+=1
                    if setup_counter<__setup_tries__:
                        print_log('ERROR at setting PAN_ID. Retrying #%d'%setup_counter)
                        clear_buffer(ser)
                        state='SETUP'
                        continue
                    else:
                        print_log('Unable to set up Zigbee network: Too many errors. Program terminates... ')
                        ser.close()
                        #sys.exit()
                        return

                print_log('PAN_ID has been set successfully')

                ## setting channel mask register
                print_log('Setting channel mask...')
                error=set_channel_mask(ser)
                if error == 0:
                    ##retrying
                    setup_counter+=1
                    if setup_counter<__setup_tries__:
                        print_log('ERROR at setting channel mask. Retrying #%d'%setup_counter)
                        clear_buffer(ser)
                        state='SETUP'
                        continue
                    else:
                        print_log('Unable to set up Zigbee network: Too many errors. Program terminates... ')
                        ser.close()
                        #sys.exit()
                        return
                    print_log('Channel mask has been set successfully')


                ## reset USB device
                print_log('Resetting Zigbee module...')
                (error,resetinfo)=reset_zigbee(ser)
                if error == 0:
                    ##retrying
                    setup_counter+=1
                    if setup_counter<__setup_tries__:
                        print_log('ERROR at resetting Zigbee module. Retrying #%d'%setup_counter)
                        clear_buffer(ser)
                        state='SETUP'
                        continue
                    else:
                        print_log('Unable to set up Zigbee network: Too many errors. Program terminates... ')
                        ser.close()
                        #sys.exit()
                        return
                print_log('Node has joined a PAN with PAN_ID:', resetinfo[8:12], 'on channel:', resetinfo[5:7])
                state='SETUP2'
                clear_buffer(ser)
                continue

            #############################################################
            ## SETUP2: setup ZigBee network, Phase 2: checking and setting network status
            #############################################################
            elif state=='SETUP2':

                ## Getting network status
                print_log('Getting network info...')
                serialwrite(ser,'AT+n?\r\n')

                ## Receiving response
                ser_in = line_limited_read(ser, 3, 5)
                print_debug('Received: ', ser_in)
                if (len(ser_in) > 1) & (ser_in[1][0:3] == '+N='):
                    USB_role = ser_in[1][3:6]
                    channel = ser_in[1][7:9]
                    PAN_ID = ser_in[1][10:14]
                    USB_power = ser_in[1][15:16]
                else:
                    USB_role = channel = PAN_ID = USB_power = None

                print_debug(USB_role, channel, PAN_ID, USB_power)

                #PAN_ID needs to be set
                if (PAN_ID != '31F4'):
                    setup_counter+=1
                    if setup_counter<__setup_tries__:
                        print_log('ERROR at getting network status. Retrying #%d'%setup_counter)
                        clear_buffer(ser)
                        state='SETUP'
                        continue
                    else:
                        print_log('Unable to set up Zigbee network: Too many errors. Program terminates... ')
                        ser.close()
                        #sys.exit()
                        return
                # network has to be reconfigured: role is incorrect
                if (USB_role!=ROLE_setting):
                    ## leaving current network
                    result=leave_pan(ser)
                    if result==1:
                        ## correct ansver
                        pass
                    else:  ## retrying network setup
                        setup_counter+=1
                        if setup_counter<__setup_tries__:
                            print_log('ERROR at getting network status. Retrying #%d'%setup_counter)
                            clear_buffer(ser)
                            state='SETUP'
                            continue
                        else:
                            print_log('Unable to set up Zigbee network: Too many errors. Program terminates... ')
                            ser.close()
                            #sys.exit()
                            return

                    ## Network is leaved at this point
                    ## if we want to form a network as a coordinator
                    if ROLE_setting=='COO':
                        # Establishin PAN_ID
                        result=est_pan_id(ser)
                        if result==1:
                            ## correct answer
                            pass
                        else:
                            setup_counter+=1
                            if setup_counter<__setup_tries__:
                                # Retrying
                                print_log('ERROR at getting network status. Retrying #%d'%setup_counter)
                                clear_buffer(ser)
                                state='SETUP'
                                continue
                            else:
                                print_log('Unable to set up Zigbee network: Too many errors. Program terminates... ')
                                ser.close()
                                #sys.exit()
                                return
                    ## if we want to form a network as a router
                    elif ROLE_setting=='FFD':
                        result=join_pan(ser)
                        if result==1:
                            ## correct answer
                            pass
                        else:
                            setup_counter+=1
                            if setup_counter<__setup_tries__:
                                # Retrying
                                print_log('ERROR at getting network status. Retrying #%d'%setup_counter)
                                clear_buffer(ser)
                                state='SETUP'
                                continue
                            else:
                                print_log('Unable to set up Zigbee network: Too many errors. Program terminates... ')
                                ser.close()
                                #sys.exit()
                                return
                    # wrong ROLE_setting
                    else:
                        ROLE_setting=='COO'
                    ## End of part of correcting wrong network setting
                    clear_buffer(ser)
                    state='SETUP2'      ## checking again
                    continue

                #Role setting is correct
                else:
                    print_log('Role is %s, PAN_ID is 0x31F4, channel is'%USB_role, channel, ', output power is', USB_power, 'dBm')

                    setup_counter=0
                    state='FINDING'

                    continue

            #############################################################
            ## FINDING: finding devices
            #############################################################
            elif state=='FINDING':

                ## Finding devices in network
                print_log('Searching for Plogg devices in network...')
                device_role_list = find_devices2(ser,expected_device_no)
                device_list=device_role_list.keys()
                print_debug('Device list2:',device_list)
                print_log('%d device(s) have been found.'%len(device_list))
                if len(device_list)==0:
                    print_log('No device has been found! Rescanning...')
                    print_log('Rescanning ...')
                    clear_buffer(ser)
                    state=='FINDING'
                    continue
                # Next state
                else:
                    getnames_counter=0
                    state='GETNAMES'
                    continue

            #############################################################
            ## GETNAMES: getting names (and topology information) of found devices
            #############################################################
            elif state=='GETNAMES':
                NAMEstart=time.time()
                print_log('Getting device names...')


                devices={}
                #initializing device_names_list if this is the first attempt
                if getnames_counter==0:
                    device_names_list={}
                    devices_to_read=copy.deepcopy(device_list)  # devices that haven't go a name yet
                ## Getting names of devices
                temporary=get_device_names(ser,devices_to_read,PAR_setting)
                #appending names to device_names_list
                for k,v in temporary.iteritems():
                    device_names_list[k]=v
                    #Deleting devices from devices_to_read
                    if k in devices_to_read:
                        devices_to_read.remove(k)

                #### handling errors in name fetching
                if len(device_names_list)!=len(device_list):
                    getnames_counter+=1
                    if getnames_counter==__getname_tries__:
                        print_log('Failed to get the names of all of the devices after the %d attempt. Some devices are ignored.'%__getname_tries__)
                        #ignoring the problematic devices
                        device_list=device_names_list.keys()
                        print_log('New device list after ignoring some:',device_list)
                    else:
                        ## retrying
                        print_log('Failed to get the name of',(len(device_list)-len(device_names_list)),'device(s). Retrying...'),
                        state=='GETNAMES'
                        continue

                getnames_counter=0
                # creating data structure, which describes the devices in the rest of the program
                for k,v in device_names_list.iteritems():
                    ## Getting topology information of nodes
                    if MAP_setting=='1':

                        ## Getting LQI, RSSI
                        print_log('Getting lqi, rssi values from %s'%v)
                        (lqi,rssi)=get_linkinfo(ser,k)

                        ## Getting list of neighbours
                        print_log('Getting neighbours of %s'%v)
                        neighbours=get_neighbours(ser,k)
                        print_debug('Neighbours of %s:'%v,neighbours)

                        # Structure is dictionary, key: EUI, value: (EUI,name,[error_counter],lqi,rssi,list of neighbours)
                        # EUI is the key value
                        devices[k]=(k,v,[0],lqi,rssi,neighbours)

                    else:
                        #EUI, name and error counter
                        # Structure is dictionary, key: EUI, value: (EUI,name,[error_counter])
                        devices[k]=(k,v,[0])

                print_log('Names of %d devices has fetched in %f seconds.'%(len(devices),time.time()-NAMEstart))

                if MAP_setting=='1':
                    state='MAPPING'
                else:
                    if RTC_setting=='1':
                        state='RTC'
                    else:
                        state='FETCHING'
                        loop_counter=0
                        fordelete=[]

                continue

            #############################################################
            ## MAPPING: discovering network topology, creating text and .png file about it
            #############################################################
            elif state=='MAPPING':
                startMAP=time.time()
                print_log('Discovering network topology...')
                #DEBUG
                print_debug('DEVICES:',devices)
                # Getting USB's EUI, name and type
                print_log('Getting EUI of USB stick...')
                (USB_name,USB_type,USB_EUI)=get_owneui(ser)
                print_log('EUI of USB stick is %s'%USB_EUI)
                # If error occurs, skips this state
                if len(USB_EUI)==0:
                    print_log('Error during discovering network topology.')
                    if RTC_setting=='1':
                        state='RTC'
                    else:
                        state='FETCHING'
                        loop_counter=0
                        fordelete=[]
                    continue
                #Correct EUI
                else:
                    pass
                    # Getting the neighbours of the USB stick
                    print_log('Getting neighbours of USB stick...')
                    nbr_table=get_ngbtable(ser,devices.keys())
                    print_debug('nbr_table:',nbr_table)
                    if len(nbr_table)==0:
                         # If error occurs, skips this state
                        print_log('Error during discovering network topology.')
                        if RTC_setting=='1':
                            state='RTC'
                        else:
                            state='FETCHING'
                            fordelete=[]
                            loop_counter=0
                        continue
                    # Correct nbr_table
                    else:

                        try:
                            #Writing network info to file
                            t=time.localtime()
                            timestring='%4d%2.2d%2.2d_%2.2d%2.2d%2.2d'%(t[0],t[1],t[2],t[3],t[4],t[5])
                            filename='maps/network_map_%s.log'%timestring
                            f_nmap=open(filename,"w")
                            f_nmap.write('ZigBee network parameters and topology at %4d. %2.2d. %2.2d. %2.2d:%2.2d.%2.2d\n\n'%(t[0],t[1],t[2],t[3],t[4],t[5]))
                            # printing information about the network
                            node_number=len(devices)+1
                            #calculating number of connections: sum(number of neighbours)/2
                            conn_number=len(nbr_table)
                            for EUI,device in devices.iteritems():
                                conn_number=conn_number+len(device[5])
                            conn_number=int(conn_number/2)
                            # printing global information about the network
                            f_nmap.write('Network information:\n\n\tPAN_ID: %s\n\tChannel: %s\n\tNumber of nodes: %d\n\tNumber of connections: %d\n\n\n'%(PAN_ID,channel,node_number,conn_number))
                            # printing information about the USB stick
                            f_nmap.write("USB stick information:\n\n\tType: %s %s\n\tRole: %s\n\tEUI: %s\n\tTransmit power: %s dBm\n\n\n"%(USB_name,USB_type,USB_role,USB_EUI,USB_power))
                            # Printing the neighbours of the USB stick

                            #Expanding 'devices' structure with the USB stick
                            devices_exp=copy.deepcopy(devices)
                            devices_exp[USB_EUI]=(USB_EUI,'USB_stick',[0],'00','---',nbr_table)

                            #DEBUG
                            print_debug('DEVICES_EXP:',devices_exp)
                            print_debug('DEVICES:',devices)
                            # Expanding device_role_list structure with the USB stick
                            device_role_list_exp=copy.deepcopy(device_role_list)
                            if (USB_role=='COO'):
                                device_role_list_exp[USB_EUI]='coordinator'
                            elif (USB_role=='FFD'):
                                device_role_list_exp[USB_EUI]='router'
                            else:
                                device_role_list_exp[USB_EUI]='unrecognised'
                            # printing information of the nodes
                            f_nmap.write('Nodes in the network: (Name | EUI | Role | LQI | RSSI)\n\n')
                            for EUI,device in devices_exp.iteritems():
                                f_nmap.write("\t%s | %s | %s | %s | %s dBm\n\t  Neighbours:"%(device[1],device[0],device_role_list_exp[device[0]],int(device[3],16),device[4]))
                                #Printing neighbours
                                for EUI in device[5]:
                                   f_nmap.write("\n\t    %s"%devices_exp[EUI][1])
                                f_nmap.write("\n\n\n")

                            # Generating graph of network topology to an image file
                            if GRAPH_setting=='1':
                                print_log('Generating topology graph...')
                                gengraph(devices_exp,device_role_list_exp,timestring)
                            #Depth-first search
                            f_nmap.write('Tree representation of the network with depth-first search:\n\n')
                            # calling recursive function
                            printed_EUI_list=[]
                            print_tree_depth(f_nmap,USB_EUI,devices_exp,printed_EUI_list,1)

                            #Breadth-first search
                            f_nmap.write('\n\nTree representation of the network with breadth-first search:\n\n')
                            # calling recursive function
                            printed_EUI_list=[USB_EUI]
                            print_tree_breadth(f_nmap,USB_EUI,devices_exp,printed_EUI_list,1)
                            f_nmap.close()

                        except IOError:
                            print_log('ERROR when writing network_map.dat! Program terminates...')
                            #sys.exit()
                            return

                print_log('Network has been mapped in %f seconds.'%(time.time()-startMAP))

                if RTC_setting=='1':
                    state='RTC'
                else:
                    state='FETCHING'
                    loop_counter=0
                    fordelete=[]
                continue

            #############################################################
            ## RTC: setting RTCs of Ploggs as the computer time
            #############################################################
            elif state=='RTC':
                print_log('Setting RTC of devices..')
                #iterating in devices dictionary
                for EUI,device in devices.iteritems():
                    print_log('Setting RTC of %s'%device[1])
                    report=set_rtc(ser,device)
                    if report:
                        print_log('RTC of %s has been set successfully.'%device[1])
                    else:
                        print_log('Error while setting RTC of %s'%device[1])

                state='FETCHING'
                loop_counter=0
                fordelete=[]
                continue

            #############################################################
            ## FETCHING: gets live info from all Ploggs periodically
            #############################################################
            elif state=='FETCHING':
                # dummy live data: filled with 'NaN'


                dummy_ld={'name':'dummy','EUI':'dummy','year':float('nan'),'month':float('nan'),'day':float('nan'),'hour':float('nan'),'min':float('nan'),'sec':float('nan'),'watts':float('nan'),'cg_watts':float('nan'),'cc_watts':float('nan'),'freq':float('nan'),'voltage':float('nan'),'current':float('nan'),'ontime':float('nan'),'vars':float('nan'),'cg_vars':float('nan'),'cc_vars':float('nan'),'phase':float('nan'),'eq_ontime':float('nan')}


                # Redirecting to MENU state if interactive mode is set in config file
                if MENU_setting=='1':
                    device_menu_list=devices.values()
                    state='MENU'
                    continue

                loop_counter+=1
                print_debug('START OF FETCHING CICLE\n')
                starttime=time.time()
                #list of devices that are need to be deleted
                fordelete=[]
                # if devices sturcure is not empty
                if len(devices)>0:
                    # if parallel communication is chosen in config file
                    if PAR_setting=='1':
                        # if semi_parallel_mode is set
                        if __semi_parallel_mode__==1:
                            dict_payloads=par_get4_binary(ser,devices.keys(),'yv')
                            print_log('Data logging (semi-parallel mode) #%d...'%loop_counter)
                        # parallel mode
                        else:
                            dict_payloads=par_get_binary2(ser,devices.keys(),'yv')
                            print_log('Data logging (parallel mode) #%d...'%loop_counter)
                        # checking if answer is complete
                        # iterating on devices
                        for k,dev in devices.iteritems():
                            # if data fetching form this device was successful
                            if dict_payloads.has_key(k):
                                live_data=binary_to_liveinfo(dict_payloads[k],devices[k][1],devices[k][0])

                                # Error
                                if (len(live_data)==0):
                                    print_log('Error while getting live data from %s'%devices[k][1])
                                    #Creating live_data dictionray with NaNs
                                    live_data=dummy_ld
                                    live_data['EUI']=k
                                    live_data['name']=devices[k][1]
                                    total_live_data[k]=live_data
                                # Successful fetching
                                else:
                                    # resetting error counter
                                    devices[k][2][0]=0
                                    # copying data
                                    total_live_data[k]=live_data
                                    #printing some fetched data
                                    print_log('%s: %-.3f W %-.3f var %d deg.'%(live_data['name'],live_data['watts'],live_data['vars'],live_data['phase']))
                                    # print live data to file --> not implemented in manager!
#                                    result=log_live_data(bus,live_data)
#                                    #if error while writing to file
#                                    if result==0:
#                                        print_log('Error while logging live data of %s'%devices[k][1])
#                                    else:
#                                        print_log('Logging live data of %s was successful'%devices[k][1])
                            # Fetching was not successful
                            else:
                                #Incrementing error counter of the device
                                devices[k][2][0]+=1
                                print_log('Error while getting live data of %s, #%d'%(devices[k][1],devices[k][2][0]))
                                live_data=dummy_ld
                                live_data['EUI']=k
                                live_data['name']=devices[k][1]
                                total_live_data[k]=live_data
                                #Removing device: append it's EUI to 'fordelete' list
                                if devices[k][2][0]==__misread_to_remove__:
                                    print_log('After the %dth unsuccessful attempt, %s is removed from the list'%(__misread_to_remove__,devices[k][1]))
                                    fordelete.append(k)

                    # serial fetching is set
                    else:
                        # iterating on devices
                        for EUI,device in devices.iteritems():

                            live_data=get_live_info2(ser,device,devices.keys())    #>>new version
                            print_debug('return:',live_data)
                            ## if fetching was not successful
                            if len(live_data)==0:
                                #Incrementing error counter of the device
                                device[2][0]+=1
                                print_log('Error while getting live data of %s, #%d'%(device[1],device[2][0]))
                                live_data=dummy_ld
                                live_data['EUI']=EUI
                                live_data['name']=device[1]
                                total_live_data[EUI]=live_data
                                #Removing device: append it's EUI to 'fordelete' list
                                if device[2][0]==__misread_to_remove__:
                                    print_log('After the %dth unsuccessful attempt, %s is removed from the list'%(__misread_to_remove__,device[1]))
                                    #devices.pop([i])
                                    #del devices[EUI]
                                    fordelete.append(EUI)

                            else:
                                #resetting error counter
                                device[2][0]=0
                                total_live_data[EUI]=live_data
                                #printing some fetched data
                                print_log('%s: %-.3f W %-.3f var %d deg.'%(live_data['name'],live_data['watts'],live_data['vars'],live_data['phase']))
                                # print live data to file --> not implemented in manager
#                                result=log_live_data(bus,live_data)
#                                #error while writing to file
#                                if result==0:
#                                    print_log('Error while getting live data of %s'%device[1])
#                                else:
#                                    print_log('Logging live data of %s was successful'%device[1])
                    # If there are devices to delete
                    if len(fordelete)>0:
                        for EUI in fordelete:
                            del devices[EUI]
                    # if __loops_to_rescan__ loops has been executed: rescanning network
                    if (loop_counter>=__loops_to_rescan__):
                        loop_counter=0

                        if MAP_setting=='1':
                            # SETUP instead of FINDING to refresh USB stick's neighbour table
                            state='SETUP'
                        else:
                            state='FINDING'
                        continue
                # len(devices)==0
                else:
                    print_log('No available devices. Rescanning...')
                    loop_counter=0
                    if MAP_setting=='1':
                        state='SETUP'
                    else:
                        state='FINDING'
                    continue


                # normal program flow continues here
                # calculating waiting time for constant period time
                endtime=time.time()
                elapsed=endtime-starttime
                remained=INT_setting-elapsed
                print_debug('starttime, endtime, elapsed, INT_setting, remained',starttime,endtime,elapsed,INT_setting,remained)
                print_log('Time of fetching: %f seconds'%elapsed)
                
                if remained>0:
                    print_log('Wait for %f seconds'%remained)
                    time.sleep(remained)

                state='FETCHING'
                continue

            ####################################################################
            ## MENU: state of interactive mode: receiving and executing commands (enbedded state machine)
            ####################################################################
            elif state=='MENU':
                #Emptying input buffer of serial port
                clear_buffer(ser)
                #Printing available devices
                print_device_list(device_menu_list)
                #Printing available commands
                print '\nAvailable commands (where X is a device index):\nvX: get live info from X, rtsX: update Real Time Clock, rX: reset accumulators,\nmX: print max values, mrX: reset max values, nX: Set Plogg name, aX: turn on device, bX: turn off device\nOr type \'exit\' to exit, \'rescan\' for searching devices or \'reset\' for resetting network'
                #reading command
                command=raw_input('Command: ')
                print_debug('Command:',command)
                ## EXIT COMMAND
                if command=='exit':
                    ser.close()
                    #sys.exit()
                    return
                ## RESCAN COMMAND
                elif command=='rescan':
                    state='FINDING'
                    continue
                ## RESET COMMAND
                elif command=='reset':
                    state='SETUP'
                    continue
                ## GET LIVE INFO COMMAND
                elif command[0]=='v':
                    if (len(command)>1) & (command[1].isdigit()):
                        if int(command[1])<len(device_menu_list):
                            #Getting live info
                            live_data=get_live_info2(ser,device_menu_list[int(command[1])],devices.keys())
                            # successful fetching
                            if len(live_data)>0:
                                print_live_data(live_data)
                            # error
                            else:
                                print '\nError while getting live data of %s'%device_menu_list[int(command[1])][1]
                            # Waiting for enter
                            raw_input('Press enter...')
                            state='MENU'
                            continue
                    # program flow if command is incorrect
                    raw_input('Wrong command. Press enter...')
                    state='MENU'
                    continue
                ## TURN ON COMMAND
                elif command[0]=='a':
                    if (len(command)>1) & (command[1].isdigit()):
                        if int(command[1])<len(device_menu_list):
                            #Turning on relay
                            report=turnon(ser,device_menu_list[int(command[1])],devices.keys())
                            if report:
                                print 'Device has been turned on successfully.'
                            else:
                                print '\nError while turning on %s'%device_menu_list[int(command[1])][1]
                            # Waiting for enter
                            raw_input('Press enter...')
                            state='MENU'
                            continue
                    # program flow if command is incorrect
                    raw_input('Wrong command. Press enter...')
                    state='MENU'
                    continue
                ## TURN OFF COMMAND
                elif command[0]=='b':
                    if (len(command)>1) & (command[1].isdigit()):
                        if int(command[1])<len(device_menu_list):
                            #Turning off relay
                            report=turnoff(ser,device_menu_list[int(command[1])],devices.keys())
                            if report:
                                print 'Device has been turned off successfully.'
                            else:
                                print '\nError while turning off %s'%device_menu_list[int(command[1])][1]
                            # Waiting for enter
                            raw_input('Press enter...')
                            state='MENU'
                            continue
                    # program flow if command is incorrect
                    raw_input('Wrong command. Press enter...')
                    state='MENU'
                    continue

                ## SETTING RTC COMMAND
                elif len(command)>3:
                    if (command[0:3]=='rts') &  command[3].isdigit():
                        if int(command[3])<len(device_menu_list):
                            # Setting RTC of a Plogg device
                            report=set_rtc(ser,device_menu_list[int(command[3])])
                            if report:
                                raw_input('RTC of %s has been set successfully. Press enter...'%device_menu_list[int(command[3])][1])
                            else:
                                raw_input('Error during setting RTC of %s. Press enter...'%device_menu_list[int(command[3])][1])
                            state='MENU'
                            continue
                     # program flow if command is incorrect
                    raw_input('Wrong command. Press enter...')
                    state='MENU'
                    continue
                ## RESET ACCUMULATORS COMMAND
                elif command[0]=='r':
                    if (len(command)>1) & (command[1].isdigit()):
                        if int(command[1])<len(device_menu_list):
                            #Resetting accumulated values
                            report=reset_acc(ser,device_menu_list[int(command[1])],devices.keys())
                            if report:
                                print '\nResetting accumulated values of %s was successful'%device_menu_list[int(command[1])][1]
                            else:
                                print '\nError while resetting accumulators of %s'%device_menu_list[int(command[1])][1]
                            # Waiting for enter
                            raw_input('Press enter...')
                            state='MENU'
                            continue
                    # program flow if command is incorrect
                    raw_input('Wrong command. Press enter...')
                    state='MENU'
                    continue
                ## SET NEW NAME COMMAND
                elif command[0]=='n':
                    if len(command)>1 & command[1].isdigit():
                        if int(command[1])<len(device_menu_list):
                            # Getting new name from user
                            newname=raw_input("Type the new name for %s:\r\n"%device_menu_list[int(command[1])][1])
                            #Setting name
                            report=setname(ser,device_menu_list[int(command[1])],devices.keys(),newname)
                            if report:
                                print '\nSetting name of %s to %s was successful'%(device_menu_list[int(command[1])][1],newname)
                            else:
                                print '\nSetting name of %s to %s has failed'%(device_menu_list[int(command[1])][1],newname)
                            # Waiting for enter
                            raw_input('Press enter...')
                            state='GETNAMES'
                            continue
                    # program flow if command is incorrect
                    raw_input('Wrong command. Press enter...')
                    state='MENU'
                    continue
                ## GET MAX VALUES COMMAND (WITH OPTIONAL RESET)
                elif command[0]=='m':
                    max_values={}
                    wrong=0 # Error flag
                    reset=0 # reset flag
                    if len(command)>1:
                        if command[1].isdigit():
                            if int(command[1])<len(device_menu_list):

                                #Getting max values without reset
                                max_values=get_max_values(ser,device_menu_list[int(command[1])],devices.keys(),0)
                                device_name=device_menu_list[int(command[1])][1]
                                reset=0
                            else:
                                wrong=1

                        elif (len(command)>2) & (command[1]=='r'):
                            if command[2].isdigit():
                                if int(command[2])<len(device_menu_list):

                                    #getting values with resetting them
                                    max_values=get_max_values(ser,device_menu_list[int(command[2])],devices.keys(),1)
                                    device_name=device_menu_list[int(command[2])][1]
                                    reset=1
                                else:
                                    wrong=1
                            else:
                                wrong=1
                        else:
                            wrong=1
                    else:
                        wrong=1

                    # handling error
                    if wrong==1:
                        raw_input('Wrong command. Press enter...')
                        state='MENU'
                        continue
                    # printing maximum values to screen
                    if len(max_values)>0:
                        if max_values.has_key('maxvoltage'):
                            print('Maximum voltage: %8.3f V at %4d. %2.2d. %2.2d. %2.2d:%2.2d.%2.2d')%(max_values['maxvoltage'][1],max_values['maxvoltage'][0][0],max_values['maxvoltage'][0][1],max_values['maxvoltage'][0][2],max_values['maxvoltage'][0][3],max_values['maxvoltage'][0][4],max_values['maxvoltage'][0][5])
                        if max_values.has_key('maxcurrent'):
                            print('Maximum current: %8.3f A at %4d. %2.2d. %2.2d. %2.2d:%2.2d.%2.2d')%(max_values['maxcurrent'][1],max_values['maxcurrent'][0][0],max_values['maxcurrent'][0][1],max_values['maxcurrent'][0][2],max_values['maxcurrent'][0][3],max_values['maxcurrent'][0][4],max_values['maxcurrent'][0][5])
                        if max_values.has_key('maxwattage'):
                            print('Maximum wattage: %8.3f W at %4d. %2.2d. %2.2d. %2.2d:%2.2d.%2.2d')%(max_values['maxwattage'][1],max_values['maxwattage'][0][0],max_values['maxwattage'][0][1],max_values['maxwattage'][0][2],max_values['maxwattage'][0][3],max_values['maxwattage'][0][4],max_values['maxwattage'][0][5])
                        if reset:
                            print 'Maximum values of %s has been reseted'%device_name
                    else:
                        print '%s has not recorded maximum values yet or error during data transfer'%device_name
                    # Waiting for enter
                    raw_input('Press enter...')
                    state='MENU'
                    continue

            ####################################################################
            ## INVALID PROGRAM STATE
            ####################################################################
            else:
                print_log('invalid program state! Program restarts...')
                ser.close()
                state='SERIAL'
                continue

        ## Handling general expression in the loop --> reset
        except Exception, err:
            print_log('Unhandled exception: %s. Restarting...'%str(err))
            state='SERIAL'


## CLASSES ##

class Pm_service(dbus.service.Object):
    ## remote procedure for getting a specified live data
    @dbus.service.method(dbus_interface='ca.amk.Interface',
                   in_signature='s', out_signature='a{sd}')
    def get_live_data(self,EUI):
        global total_live_data

        print_log('Request for live_data with %s EUI'%(EUI))
        #slicing dictionary
        #live_data_string={'EUI':liveinfo['EUI'],'name':liveinfo['name']}
        live_data_float=copy.deepcopy(total_live_data[EUI]);
        del live_data_float['EUI']
        del live_data_float['name']
        #print_log('returned value: ',live_data_float)
        return live_data_float
    ## remote procedure for getting device list
    @dbus.service.method(dbus_interface='ca.amk.Interface',
                   in_signature='i', out_signature='a{ss}')
    def get_device_EUIs(self,input):
        global devices
        print_log('Device list has sent to another script.')
        short_devices={}
        for k,v in devices.iteritems():
            short_devices[k]=v[1]
    
        return short_devices

    @dbus.service.method(dbus_interface='ca.amk.Interface',
                   in_signature='i', out_signature='i')
    def get_sampling_iv(self,input):
        global INT_setting
        return INT_setting




## THREADS ##
class thr_manager(threading.Thread):
    def run(self):
        main()

class thr_server(threading.Thread):
    def run(self):
        #global live_data
 #       print 'Server thread is started.'
        bus = dbus.SessionBus()
        name = dbus.service.BusName('ca.amk.pm_service', bus=bus)
        obj = Pm_service(name, '/')
        loop = gobject.MainLoop()
        gobject.threads_init()
        print_log('Server thread is listening...')
        loop.run()


if __name__ == "__main__":
    #main()
    print_log('Starting manager thread...')
    thr_manager().start()
    print_log('Manager thread has been started.')
    print_log('Starting server thread...')
    thr_server().start()
    print_log('Server thread has been started.')






